home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UMacTcp.cp < prev    next >
Encoding:
Text File  |  1994-04-12  |  19.0 KB  |  706 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UMacTcp.cp
  3.  
  4. #include "UMacTcp.h"
  5.  
  6. #include "AddressXlation.h"
  7. #include "GetMyIPAddr.h"
  8. #include "UThread.h"
  9. #include "UProgress.h"
  10. #include "Tools.h"
  11. #include "UFatalError.h"
  12.  
  13. #include <ErrorGlobals.h>
  14.  
  15. #ifndef __STDIO__
  16. #include <stdio.h>
  17. #endif
  18.  
  19. #include <Traps.h>
  20. #include <SysEqu.h>
  21. #include <OSUtils.h>
  22.  
  23. #pragma segment MyComm
  24.  
  25. const long kStreamBufferSize = 8 * 1024;
  26.  
  27. #if qDebug
  28. #define macroCheck(x) x
  29. #else
  30. #define macroCheck(x)
  31. #endif
  32.  
  33. #define qDebugActivity qDebug & 0
  34.  
  35. short gMacTCPID = 100;
  36. //--------------------------------------------------------------------------------------------
  37.  
  38. short gMacTcpRefNum = 0;
  39. long gMyIP = 0;
  40. CStr255 gMyDotName("");
  41. Boolean gResolverIsOpen = false;
  42. TrapPatch gKillMacTCPPatch;
  43. TLongintList *gMacTCPList = nil;
  44. long gNuntiusA5 = nil;
  45.  
  46. #pragma push
  47. #pragma trace off
  48. #pragma segment A5Ref
  49. char gResolverDone; 
  50. // 'done' may not be on stack as it can be swapped out 
  51. // and the variable is accessed from interrupt!
  52. pascal void DNRResultProc(struct hostInfo* /* hInfoPtr */,char *userDataPtr)
  53. {
  54.     *userDataPtr = 0xff;
  55. }
  56. #pragma pop
  57.  
  58. #pragma segment A5Ref
  59. void InitUMacTCP()
  60. {
  61.     // Placed in A5Ref to get the segment loaded so _LoadSeg called on that
  62.     // segment. Otherwise it will be called at interrupt time :-(
  63.     short errNo = OpenDriver(".IPP", gMacTcpRefNum);
  64.     if (errNo != noErr)
  65.         Failure(errNo, messageCannotOpenMacTcp);
  66.     gNuntiusA5 = *(long*)CurrentA5; // low mem global
  67.     TLongintList *lList = new TLongintList();
  68.     lList->ILongintList();
  69.     gMacTCPList = lList;
  70.     FailOSErr(HeadPatch(gKillMacTCPPatch, _ExitToShell, (void*)StripLong(KillMacTCPStuff)));
  71. }
  72.  
  73. #pragma segment MyComm
  74. void CloseDownUMacTCP()
  75. {
  76.     if (gResolverIsOpen)
  77.     {
  78.         gResolverIsOpen = false;
  79.         OSErr err = CloseResolver();
  80. #if qDebug
  81.         if (err)
  82.         {
  83.             fprintf(stderr, "Got error when closing resolver: %ld\n", long(err));
  84.             ProgramBreak(gEmptyString);
  85.         }
  86. #endif
  87.     }
  88.     gMacTcpRefNum = 0;
  89. }
  90.  
  91. long MyIP()
  92. {
  93.     if (!gMacTcpRefNum)
  94.         return 0x01020304;
  95.     if (gMyIP)
  96.         return gMyIP;
  97.     GetAddrParamBlock pb;
  98.     BlockSet(Ptr(&pb), sizeof(pb), 0);
  99.     pb.csCode = ipctlGetAddr;
  100.     pb.ioCRefNum = gMacTcpRefNum;
  101.     FailOSErr(PBControlSync(ParmBlkPtr(&pb)));
  102.     gMyIP = pb.ourAddress;
  103. #if qDebug
  104.     fprintf(stderr, "My IP# is %ld.%ld.%ld.%ld\n", (gMyIP >> 24) & 255, (gMyIP >> 16) & 255, (gMyIP >> 8) & 255, gMyIP & 255);
  105. #endif
  106.     return gMyIP;
  107. }
  108.  
  109. void GetMyDotName(CStr255 &myDotName)
  110. {
  111.     if (!gMacTcpRefNum)
  112.     {
  113.         myDotName = gMyDotName = "alone.in.world";
  114.         return;
  115.     }
  116.     if (!gMyDotName.Length())
  117.     {
  118.         FailInfo fi;
  119.         if (fi.Try())
  120.         {
  121.             IP2DotName(MyIP(), gMyDotName);
  122. #if qDebug
  123.             fprintf(stderr, "My dotname is %s\n", (char*)gMyDotName);
  124. #endif
  125.             fi.Success();
  126.         }
  127.         else // fail
  128.         {
  129.             if (fi.error == authNameErr)
  130.                 Failure(errMyMacHasNoDotName, fi.message);
  131.             else
  132.                 fi.ReSignal();
  133.         }
  134.     }
  135.     myDotName = gMyDotName;
  136. }    
  137.  
  138. void IP2DotName(long ip, CStr255 &name)
  139. {
  140. #if qDebug
  141.     char IP[50];
  142.     sprintf(IP, "%ld.%ld.%ld.%ld", (ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
  143.     fprintf(stderr, "ip -> name of %s\n", IP);
  144. #endif
  145.     static IP2DotNameBusy = false;
  146.     if (IP2DotNameBusy)
  147.     {
  148. #if qDebug
  149.         fprintf(stderr, "Waits for previous IP2DotName to complete...\n");
  150. #endif
  151.         while (IP2DotNameBusy)
  152.             gCurThread->YieldTime(); 
  153.     }
  154.     IP2DotNameBusy = true;
  155.     Boolean wasDisabled = gCurProgress->SetAbortDisable(true);
  156.     VOLATILE(wasDisabled);
  157.     FailInfo fi;
  158.     if (fi.Try())
  159.     {
  160.         static hostInfo theHostInfo; // may not be on stack, like gResolverDone!
  161.         if (!gResolverIsOpen)
  162.         {
  163. #if qDebug
  164.             fprintf(stderr, "Opens Resolver...\n");
  165. #endif
  166.             FailOSErr(OpenResolver(nil));
  167.             gResolverIsOpen = true;
  168.         }
  169.         gResolverDone = false;
  170. #if qDebug
  171.         fprintf(stderr, "Executes ip -> name of %s\n", IP);
  172. #endif
  173.         OSErr err = AddrToName(ip, &theHostInfo, DNRResultProc, &gResolverDone);
  174.         if (err == cacheFault)
  175.         {
  176. #if qDebug
  177.             fprintf(stderr, "MacTCP asks nameserver about name for %s (cacheFault)\n", IP);
  178. #endif
  179.             while (!gResolverDone)
  180.                 gCurThread->YieldTime(); 
  181.         }
  182.         else 
  183.             FailOSErr(err);
  184.         err = short(theHostInfo.rtnCode);
  185. #if qDebug
  186.         if (err != noErr)
  187.             fprintf(stderr, "Error from theHostInfo.rtnCode = %ld\n", long(err));
  188. #endif
  189.         if (err != cacheFault)
  190.             FailOSErr(err);
  191.         gCurProgress->SetAbortDisable(wasDisabled);
  192.         theHostInfo.cname[254] = 0;
  193.         name.Length() = strlen(theHostInfo.cname);
  194.         BytesMove(theHostInfo.cname, &name[1], strlen(theHostInfo.cname));
  195.         if (name.Length() && name[name.Length()] == '.')
  196.             name.Length()--;
  197. #if qDebug
  198.         fprintf(stderr, "IP2DotName: %s -> %s\n", IP, (char*)name);
  199. #endif
  200.         long ll;
  201.         if (sscanf(theHostInfo.cname, "%ld.%ld.%ld.%ld", &ll, &ll, &ll, &ll) == 4)
  202.         {
  203. #if qDebug
  204.             fprintf(stderr, "Just got dotnumber as response, not accepted!\n");
  205. #endif
  206.             FailOSErr(authNameErr); // got dotnumber and not name...
  207.         }
  208.         IP2DotNameBusy = false;
  209.         fi.Success();
  210.     }
  211.     else // fail
  212.     {
  213.         gCurProgress->SetAbortDisable(wasDisabled);
  214.         IP2DotNameBusy = false;
  215.         fi.ReSignal();
  216.     }
  217. }
  218.  
  219. long DotName2IP(const CStr255 &name)
  220. {
  221.     char cname[300];
  222.     cname[name.Length()] = 0;
  223.     BytesMove((char*)name, cname, name.Length());
  224.     // can't abort DNR calls...
  225.     Boolean wasDisabled = gCurProgress->SetAbortDisable(true);
  226.     VOLATILE(wasDisabled);
  227.     FailInfo fi;
  228.     if (fi.Try())
  229.     {
  230.         if (!gResolverIsOpen)
  231.         {
  232.             FailOSErr(OpenResolver(nil));
  233.             gResolverIsOpen = true;
  234.         }
  235.         gResolverDone = false;
  236.         static hostInfo theHostInfo; // may not be on the stack, like gResolverDone!
  237.         short err = StrToAddr(name, &theHostInfo, &DNRResultProc, &gResolverDone);
  238.         if (err == cacheFault)
  239.         {
  240. #if qDebug
  241.             fprintf(stderr, "MacTCP asks nameserver about IP for %s\n", (char*)name);
  242. #endif
  243.             err = noErr;
  244.             while (!gResolverDone)
  245.                 gCurThread->YieldTime(); 
  246.         }
  247.         FailOSErr(err);
  248.         err = short(theHostInfo.rtnCode);
  249.         if (err != cacheFault)
  250.             FailOSErr(err);
  251.         long ip = theHostInfo.addr[0];
  252.         if (ip == 0 || ip == 0xFFFFFFFF)
  253.             FailOSErr(authNameErr);
  254.         gCurProgress->SetAbortDisable(wasDisabled);
  255. #if qDebug
  256.         fprintf(stderr, "DotName2IP: %s -> %ld.%ld.%ld.%ld\n", (char*)name, (ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
  257. #endif
  258.         fi.Success();
  259.         return ip;
  260.     }
  261.     else // fail
  262.     {
  263.         gCurProgress->SetAbortDisable(wasDisabled);
  264.         fi.ReSignal();
  265.     }
  266. }
  267.     
  268.  
  269. //=================================== PanicKill ============================================
  270. #pragma push
  271. #pragma trace off
  272. #pragma segment A5Ref
  273.  
  274. pascal void KillMacTCPStuff() // must be pascal due to patch code
  275. {
  276.     if (!gMacTCPList) // before patching A5!
  277.         return; // ups
  278. #if !qModelFarData
  279. #error "This code only works as model far data"
  280. #endif
  281.     long oldA5 = SetA5(gNuntiusA5); // it works as gNuntiusA5 is referenced as 32 bit imm. addr
  282.     FailInfoPtr oldTopHandler = gTopHandler;
  283.     gTopHandler = nil;
  284.     for (ArrayIndex index = gMacTCPList->fSize; index > 0; index--)
  285.     {
  286.         PTcpStream *mtcp = *(PTcpStream**)gMacTCPList->TLongintList::ComputeAddress(index);
  287.         if (IsPtrObject(mtcp))
  288.             mtcp->CloseConnection(false);
  289.     }
  290.     gTopHandler = oldTopHandler;
  291.     SetA5(oldA5);
  292. }
  293. #pragma pop
  294. //=================================== PTcpStream ============================================
  295.  
  296.  
  297. #pragma segment MyComm
  298. PTcpStream::PTcpStream()
  299. {
  300.     fConnectionIsOpen = false;
  301.     fStreamIsOpen = false;
  302.     fStreamP = nil; // not mine
  303.     fStreamBufferP = nil;
  304.     fHostIP = 0;
  305.     fHostPort = 0;
  306. }
  307.  
  308. void PTcpStream::ITcpStream(long timeoutSecs)
  309. {
  310.     FailInfo fi;
  311.     if (fi.Try())
  312.     {
  313.         fMacTCPID = ++gMacTCPID;
  314.         gMacTCPList->InsertLast(long(this));
  315.         fTimeoutTicks = timeoutSecs * 60;
  316.         fTimeoutSecs = timeoutSecs;
  317.  
  318.         BlockSet(Ptr(&fStreamPB), sizeof(fStreamPB), 0);
  319.         BlockSet(Ptr(&fOpenPB), sizeof(fOpenPB), 0);
  320.         BlockSet(Ptr(&fClosePB), sizeof(fClosePB), 0);
  321.         BlockSet(Ptr(&fAbortPB), sizeof(fAbortPB), 0);
  322.         BlockSet(Ptr(&fReceivePB), sizeof(fReceivePB), 0);
  323.         BlockSet(Ptr(&fSendPB), sizeof(fSendPB), 0);
  324.         BlockSet(Ptr(&fStatusPB), sizeof(fStatusPB), 0);
  325.  
  326.         fReceivePB.ioResult = noErr; // signal that previous command has ended
  327.         fReceivePB.csParam.receive.rcvBuffLen = 0; // nothing received
  328.  
  329.         fWdsEntry[0].ptr = nil;
  330.         fWdsEntry[0].length = 0;
  331.         fWdsEntry[1].ptr = nil;
  332.         fWdsEntry[1].length = 0;
  333.     
  334.         fStreamBufferP = NewPermPtr(kStreamBufferSize);
  335.         if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, created at $%lx\n", fMacTCPID, this);
  336.         fi.Success();
  337.     }
  338.     else // fail
  339.     {
  340.         FreeIfPtrObject(this);
  341.         fi.ReSignal();
  342.     }
  343. }
  344.  
  345. PTcpStream::~PTcpStream()
  346. {
  347.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Going disposing\n", fMacTCPID);
  348.     gMacTCPList->Delete(long(this));
  349.     if (fStreamBufferP)
  350.         CloseConnection(false);
  351.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Disposed.\n", fMacTCPID);
  352.     fStreamBufferP = DisposeIfPtr(fStreamBufferP);
  353. }
  354.  
  355. //=================================== Tools ============================================
  356. void PTcpStream::WaitForCompletion(TCPiopb &pb)
  357. {
  358.     FailInfo fi;
  359.     if (fi.Try())
  360.     {
  361.         if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, WaitForCompl\n", fMacTCPID);
  362.         while (pb.ioResult == inProgress || pb.ioResult == connectionClosing)
  363.             gCurThread->YieldTime();
  364.         if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, WaitForCompl done\n", fMacTCPID);
  365.         fi.Success();
  366.     }
  367.     else // fail
  368.     {
  369. #if qDebug
  370.         fprintf(stderr, "Aborts MacTCP operation\n");
  371. #endif
  372.         fi.ReSignal();
  373.     }
  374. }
  375. //================= STREAM ==========================================
  376. #pragma push
  377. #pragma trace off
  378. #pragma segment A5Ref
  379. void pascal DummyASR(StreamPtr, unsigned short,
  380.         Ptr, unsigned short, struct ICMPReport *)
  381. {
  382. }
  383. #pragma pop
  384.  
  385. void PTcpStream::TCPCreateStream()
  386. {
  387.     if (fStreamIsOpen)
  388.     {
  389.         ReportFatalError("PTcpStream::TCPCreateStream, has already opened a stream");
  390.         Failure(minErr, 0);
  391.     }
  392.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Creates Stream\n", fMacTCPID);
  393.     BlockSet(Ptr(&fStreamPB), sizeof(fStreamPB), 0);
  394.     fStreamPB.csCode = TCPCreate;
  395.     fStreamPB.ioCRefNum = gMacTcpRefNum;
  396.     fStreamPB.csParam.create.rcvBuff = fStreamBufferP;
  397.     fStreamPB.csParam.create.rcvBuffLen = kStreamBufferSize;
  398.     fStreamPB.csParam.create.notifyProc = &DummyASR;
  399.     PBControlSync(ParmBlkPtr(&fStreamPB));
  400.     FailOSErr(fStreamPB.ioResult);
  401.     fStreamP = fStreamPB.tcpStream;
  402.     fStreamIsOpen = true;
  403. }
  404.  
  405. void PTcpStream::TCPReleaseStream()
  406. {
  407.     if (!fStreamIsOpen)
  408.         return;
  409.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Releases Stream\n", fMacTCPID);
  410.     fStreamIsOpen = false;
  411.     BlockSet(Ptr(&fStreamPB), sizeof(fStreamPB), 0);
  412.     fStreamPB.csCode = TCPRelease;
  413.     fStreamPB.ioCRefNum = gMacTcpRefNum;
  414.     fStreamPB.tcpStream = fStreamP;
  415.     fStreamP = nil; // not mine
  416.     PBControlSync(ParmBlkPtr(&fStreamPB));
  417.     FailOSErr(fStreamPB.ioResult);
  418. }
  419.  
  420. //================= OPEN/CLOSE ==========================================
  421. void PTcpStream::TCPOpenConnection()
  422. {
  423.     if (fOpenPB.ioResult != noErr)
  424.     {
  425.         ReportFatalError("PTcpStream::TCPOpenConnection, fOpenPB is already busy");
  426.         Failure(minErr, 0);
  427.     }
  428.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Opens connection\n", fMacTCPID);
  429.     BlockSet(Ptr(&fOpenPB), sizeof(fOpenPB), 0);
  430.     fOpenPB.csCode = TCPActiveOpen;
  431.     fOpenPB.ioResult = 1;
  432.     fOpenPB.ioCRefNum = gMacTcpRefNum;
  433.     fOpenPB.tcpStream = fStreamP;
  434.     fOpenPB.csParam.open.ulpTimeoutValue = (unsigned char)Min(200, fTimeoutSecs);
  435.     fOpenPB.csParam.open.ulpTimeoutAction = 1;
  436.     fOpenPB.csParam.open.validityFlags = 0xC0;
  437.     fOpenPB.csParam.open.commandTimeoutValue = (unsigned char)Min(200, fTimeoutSecs);
  438.     fOpenPB.csParam.open.remoteHost = fHostIP;
  439.     fOpenPB.csParam.open.remotePort = fHostPort;
  440.     fOpenPB.csParam.open.localPort = 0;
  441.     fOpenPB.csParam.open.tosFlags = 0;
  442.     fOpenPB.csParam.open.precedence = 0;
  443.     fOpenPB.csParam.open.dontFrag = 0;
  444.     fOpenPB.csParam.open.timeToLive = 0;
  445.     fOpenPB.csParam.open.security = 0;
  446.     fOpenPB.csParam.open.optionCnt = 0;
  447.     long startTick = TickCount();
  448.     FailOSErr(PBControlAsync(ParmBlkPtr(&fOpenPB)));
  449.     WaitForCompletion(fOpenPB);
  450.     long ticks = TickCount() - startTick; // made because MacTCP returns timeOut as openFailed
  451.     if (ticks >= fTimeoutTicks - 30)
  452.         FailOSErr(errOpenCommandTimeout);
  453.     else
  454.         FailOSErr(fOpenPB.ioResult);
  455.     fConnectionIsOpen = true;
  456. }
  457.  
  458. // CloseConnection aborts the connection if it could not be closed
  459. void PTcpStream::TCPCloseConnection(Boolean async)
  460. {
  461.     fConnectionIsOpen = false;
  462.     if (gCurThread->IsAborted()) // don't yield if we get aborted in first second
  463.         async = false;
  464.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Closes connection, async = %ld\n", fMacTCPID, long(async));
  465.     BlockSet(Ptr(&fClosePB), sizeof(fClosePB), 0);
  466.     fClosePB.csCode = TCPClose;
  467.     fClosePB.ioCRefNum = gMacTcpRefNum;
  468.     fClosePB.tcpStream = fStreamP;
  469.     if (async)
  470.         fClosePB.csParam.close.ulpTimeoutValue = (unsigned char)Max(20, fTimeoutSecs);
  471.     else
  472.         fClosePB.csParam.close.ulpTimeoutValue = 2;
  473.     fClosePB.csParam.close.validityFlags = 0xC0;
  474.     fClosePB.csParam.close.ulpTimeoutAction = 1; // 0 == report, 1 == abort
  475.     OSErr err = PBControl(ParmBlkPtr(&fClosePB), async);
  476.     if (err == noErr && async)
  477.     {
  478.         WaitForCompletion(fClosePB);
  479.         err = fClosePB.ioResult;
  480.     }
  481.     if (err != connectionDoesntExist && err != connectionTerminated) 
  482.         FailOSErr(err);
  483. }
  484.  
  485. void PTcpStream::TCPAbortConnection()
  486. {
  487. #if qDebug
  488.     fprintf(stderr, "Aborts TCP/IP connection\n");
  489. #endif
  490.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Aborts connection\n", fMacTCPID);
  491.     BlockSet(Ptr(&fAbortPB), sizeof(fAbortPB), 0);
  492.     fAbortPB.csCode = TCPAbort;
  493.     fAbortPB.ioCRefNum = gMacTcpRefNum;
  494.     fAbortPB.tcpStream = fStreamP;
  495.     PBControlSync(ParmBlkPtr(&fAbortPB));
  496.     if (fAbortPB.ioResult == noErr || fAbortPB.ioResult == connectionDoesntExist || fAbortPB.ioResult == connectionTerminated) 
  497.         return;
  498. #if qDebug
  499.     fprintf(stderr, "Got error when aborting connection: %ld\n", long(fAbortPB.ioResult));
  500. #endif
  501.     FailOSErr(fAbortPB.ioResult);
  502. }
  503.  
  504. void PTcpStream::TCPCloseOrAbortConnection(Boolean async)
  505. {
  506.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, Close || Aborts connection\n", fMacTCPID);
  507.     FailInfo fi;
  508.     if (fi.Try())
  509.     {
  510.         TCPCloseConnection(async);
  511.         fi.Success();
  512.         return;
  513.     }
  514.     else // fail
  515.     {
  516. #if qDebug
  517.         fprintf(stderr, "PTcpStream::TCPCloseOrAbortConnection, error at close = %ld\n", long(fi.error));
  518. #endif
  519.     }
  520.     // now try with abort
  521.     if (fi.Try())
  522.     {
  523.         TCPAbortConnection();
  524.         fi.Success();
  525.         return;
  526.     }
  527.     else // fail
  528.     {
  529. #if qDebug
  530.         fprintf(stderr, "PTcpStream::TCPCloseOrAbortConnection, error at abort = %ld\n", long(fi.error));
  531. #endif
  532.     }
  533. }
  534. //=========== LOW LEVEL SEND/RECEIVE ===================================================
  535. void PTcpStream::TCPSendData()
  536. {    
  537.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, TCPSendData\n", fMacTCPID);
  538.     BlockSet(Ptr(&fSendPB), sizeof(fSendPB), 0);
  539.     fSendPB.csCode = TCPSend;
  540.     fSendPB.ioCRefNum = gMacTcpRefNum;
  541.     fSendPB.tcpStream = fStreamP;
  542.     fSendPB.csParam.send.ulpTimeoutValue = (unsigned char)Min(200, fTimeoutSecs);
  543.     fSendPB.csParam.send.ulpTimeoutAction = 1; // 0 == report, 1 == abort
  544.     fSendPB.csParam.send.validityFlags = 0xC0;
  545.     fSendPB.csParam.send.pushFlag = true; // send it at once
  546.     fSendPB.csParam.send.urgentFlag = false;
  547.     fSendPB.csParam.send.wdsPtr = Ptr(fWdsEntry);
  548.     FailOSErr(PBControlAsync(ParmBlkPtr(&fSendPB)));
  549.     WaitForCompletion(fSendPB);
  550.     FailOSErr(fSendPB.ioResult);
  551.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, TCPSendData done\n", fMacTCPID);
  552. }
  553.  
  554. void PTcpStream::TCPReceiveData(void *bufferP, unsigned short bufferSize,
  555.                                     short &bytesReceived)
  556. {
  557.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, TCPReceiveData\n", fMacTCPID);
  558.     bytesReceived = 0;
  559.     BlockSet(Ptr(&fReceivePB), sizeof(fReceivePB), 0);
  560.     fReceivePB.csCode = TCPRcv;
  561.     fReceivePB.ioCRefNum = gMacTcpRefNum;
  562.     fReceivePB.tcpStream = fStreamP;
  563.     fReceivePB.csParam.receive.commandTimeoutValue = 10;
  564.     fReceivePB.csParam.receive.rcvBuff = Ptr(bufferP);
  565.     fReceivePB.csParam.receive.rcvBuffLen = bufferSize;
  566.     FailOSErr(PBControlSync(ParmBlkPtr(&fReceivePB)));
  567.     FailOSErr(fReceivePB.ioResult);
  568.     bytesReceived = fReceivePB.csParam.receive.rcvBuffLen;
  569.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, TCPReceiveData done, got %ld\n", fMacTCPID, long(bytesReceived));
  570. }
  571.  
  572. long PTcpStream::TCPNumBytesAvailable()
  573. {
  574.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, TCPNumBytesAvailable\n", fMacTCPID);
  575.     BlockSet(Ptr(&fStatusPB), sizeof(fStatusPB), 0);
  576.     fStatusPB.csCode = TCPStatus;
  577.     fStatusPB.ioCRefNum = gMacTcpRefNum;
  578.     fStatusPB.tcpStream = fStreamP;
  579.     FailOSErr(PBControlSync(ParmBlkPtr(&fStatusPB)));
  580.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, TCPNumBytesAvailable done = %ld\n", fMacTCPID, long(fStatusPB.csParam.status.amtUnreadData));
  581.     return fStatusPB.csParam.status.amtUnreadData;
  582. }
  583.  
  584. void PTcpStream::DebugCheckWds()
  585. {
  586. #if qDebug
  587.     Boolean badWDS = false;
  588.     if (fWdsEntry[1].ptr || fWdsEntry[1].length)
  589.     {
  590.         fprintf(stderr, "fWdsEntry[1].ptr at $%lx is invalid\n", fWdsEntry);
  591.         badWDS = true;
  592.     }
  593.     if (fWdsEntry[0].ptr == 0 || fWdsEntry[0].length <= 0 || fWdsEntry[0].length > 32000)
  594.     {
  595.         fprintf(stderr, "fWdsEntry[0] at $%lx is invalid\n", fWdsEntry);
  596.         badWDS = true;
  597.     }
  598.     if (badWDS)
  599.     {
  600.         fprintf(stderr, "WDS: \n");
  601.         fprintf(stderr, " 0: ptr = $%lx, len = %ld\n", fWdsEntry[0].ptr, fWdsEntry[0].length);
  602.         fprintf(stderr, " 1: ptr = $%lx, len = %ld\n", fWdsEntry[1].ptr, fWdsEntry[1].length);
  603.         ProgramBreak(gEmptyString);
  604.     }
  605. #endif
  606. }
  607.  
  608. //========= HighLevel Open/Close ============================================================
  609.  
  610. void PTcpStream::OpenConnection(long hostIP, short port)
  611. {
  612.     if (fConnectionIsOpen)
  613.         return;
  614.     if (!fStreamIsOpen)
  615.         TCPCreateStream();
  616.     fHostIP = hostIP;
  617.     fHostPort = port;
  618.     TCPOpenConnection();
  619. }
  620.  
  621. void PTcpStream::CloseConnection(Boolean async)
  622. {
  623.     FailInfo fi;
  624.     if (fConnectionIsOpen) 
  625.     {
  626.         if (fi.Try())
  627.         {
  628.             TCPCloseOrAbortConnection(async);
  629.             fi.Success();
  630.         }
  631.         else // fail
  632.         {
  633.             switch (fi.error) 
  634.             {
  635.                 case connectionTerminated:
  636.                 case connectionDoesntExist:
  637.                     break; // ignore them
  638.                 default:
  639. #if qDebug
  640.                     fprintf(stderr, "PTcpStream::CloseConnection, very unexpected: got signal when closing connection, err = %ld\n", fi.error);
  641. #endif
  642.                     break;
  643.             }
  644.         }
  645.     }
  646.     fHostIP = 0;
  647.     fHostPort = 0;
  648.     if (fStreamIsOpen)
  649.     {
  650.         if (fi.Try())
  651.         {
  652.             TCPReleaseStream();
  653.             fi.Success();
  654.         }
  655.         else // fail
  656.         {
  657. #if qDebug
  658.             fprintf(stderr, "PTcpStream::CloseConnection, very unexpected: got signal when releasing stream, err = %ld\n", fi.error);
  659. #endif
  660.         }
  661.     }
  662. }
  663.  
  664. //=========== HIGH LEVEL SEND/RECEIVE ==================================================
  665.  
  666. void PTcpStream::SendData(void *bufferP, long len)
  667. {
  668.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, SendData of %ld\n", fMacTCPID, len);
  669.     const char *p = (const char*)bufferP;
  670.     const long kMaxPartLen = 8 * 1024;
  671.     while (len > 0) 
  672.     {
  673.         short partLen = short(Min(len, kMaxPartLen));
  674.         fWdsEntry[0].ptr = p;
  675.         fWdsEntry[0].length = partLen;
  676.         fWdsEntry[1].ptr = 0;
  677.         fWdsEntry[1].length = 0;
  678.         macroCheck(DebugCheckWds());
  679.         TCPSendData();
  680.         macroCheck(DebugCheckWds());
  681.         p += partLen;
  682.         len -= partLen;
  683.     }
  684.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, SendData done\n", fMacTCPID);
  685. }
  686.  
  687. void PTcpStream::ReceiveSomeData(void *bufferP, long bufferSize, long &bytesReceived)
  688. {
  689.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, ReceiveSomeData\n", fMacTCPID);
  690.     bufferSize = Min(30000, bufferSize); // is short in MacTCP
  691.     while (true)
  692.     {
  693.         long toRead = Min(bufferSize, TCPNumBytesAvailable());
  694.         if (toRead > 0)
  695.         {
  696.             short noBytes;
  697.             TCPReceiveData(bufferP, short(toRead), noBytes);
  698.             bytesReceived = noBytes;
  699.             if (bytesReceived)
  700.                 break;
  701.         }
  702.         gCurThread->YieldTime();
  703.     }
  704.     if (qDebugActivity) fprintf(stderr, "MacTCP id %ld, ReceiveSomeData done = %ld\n", fMacTCPID, bytesReceived);
  705. }
  706.